package com.xuelang.pipeline.client.common.util;


import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URL;
import java.util.Map;

/**
 * HttpHelper
 *
 * @author xiwen.zxg
 * @since 2024/5/15
 */
@Slf4j
public class HttpHelper {

    RestTemplate restTemplate;

    public HttpHelper(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    /**
     * POST请求
     *
     * @param url
     * @param requestBean
     * @param responseBeanClass
     * @return
     * @param <T>
     * @param <U>
     */
    public <T, U> U postRequest(String url, T requestBean, Class<U> responseBeanClass) {
        return sendRequest(url, HttpMethod.POST, requestBean, responseBeanClass);
    }

    /**
     * GET请求
     *
     * @param url
     * @param requestBean
     * @param responseBeanClass
     * @return
     * @param <T>
     * @param <U>
     */
    public <T, U> U getRequest(String url, T requestBean, Class<U> responseBeanClass) {
        return sendRequest(url, HttpMethod.GET, requestBean, responseBeanClass);
    }

    /**
     * PUT请求
     *
     * @param url
     * @param requestBean
     * @param responseBeanClass
     * @return
     * @param <T>
     * @param <U>
     */
    public <T, U> U putRequest(String url, T requestBean, Class<U> responseBeanClass) {
        return sendRequest(url, HttpMethod.PUT, requestBean, responseBeanClass);
    }

    /**
     * DELETE请求
     *
     * @param url
     * @param requestBean
     * @param responseBeanClass
     * @return
     * @param <T>
     * @param <U>
     */
    public <T, U> U deleteRequest(String url, T requestBean, Class<U> responseBeanClass) {
        return sendRequest(url, HttpMethod.DELETE, requestBean, responseBeanClass);
    }

    /**
     * PATCH请求
     *
     * @param url
     * @param requestBean
     * @param responseBeanClass
     * @return
     * @param <T>
     * @param <U>
     */
    public <T, U> U patchRequest(String url, T requestBean, Class<U> responseBeanClass) {
        return sendRequest(url, HttpMethod.PATCH, requestBean, responseBeanClass);
    }

    /**
     * 发送请求
     *
     * @param url   请求地址
     * @param method    请求方法
     * @param requestBean 请求参数
     * @param responseBeanClass 响应实体类型
     *
     * @return
     * @param <T>   请求参数类型
     * @param <U>   响应参数类型
     */
    public <T, U> U sendRequest(String url, HttpMethod method, T requestBean, Class<U> responseBeanClass) {
        return sendRequest(url, null, method, requestBean, responseBeanClass);
    }

    /**
     * 发送请求
     *
     * @param url   请求地址
     * @param method    请求方法
     * @param requestBean 请求参数
     * @param responseBeanClass 响应实体类型
     * @param uriVariables  URL动态变量
     *
     * @return
     * @param <T>   请求参数类型
     * @param <U>   响应参数类型
     */
    public <T, U> U sendRequest(String url, Map<String, ?> uriVariables, HttpMethod method, T requestBean, Class<U> responseBeanClass) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        HttpEntity<T> httpEntity = new HttpEntity<T>(requestBean, headers);

        try {
            ResponseEntity<U> result = null;
            log.info("------------------------------------------------");
            if (null == uriVariables) {
                URI uri = null;
                if (url.contains("@")) {
                    URL urlObj = new URL(url);
                    uri = new URI(urlObj.getProtocol(), null, urlObj.getHost(), urlObj.getPort(), urlObj.getPath(), urlObj.getQuery(), null);
                } else {
                    uri = URI.create(url);
                }
                log.info("真实发出URI地址为: {}", uri.getPath());
                result = restTemplate.exchange(uri, method, httpEntity, responseBeanClass);
            } else {
                log.info("真实发出Url地址为: {}", url);
                result = restTemplate.exchange(url, method, httpEntity, responseBeanClass, uriVariables);
            }
            log.info("------------------------------------------------");
            return result.getBody();
        } catch (HttpClientErrorException httpClientErrorException) {
            String responseBody = httpClientErrorException.getResponseBodyAsString();
            return JSON.parseObject(responseBody, responseBeanClass);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 发送请求
     *
     * @param url   请求地址
     * @param method    请求方法
     * @param requestBean 请求参数
     * @param responseBeanClass 响应实体类型
     * @param uriVariables  URL动态变量
     *
     * @return
     * @param <T>   请求参数类型
     * @param <U>   响应参数类型
     */
    public <T, U> ResponseEntity<U> exchangeRequest(String url, Map<String, ?> uriVariables, HttpMethod method, T requestBean, Class<U> responseBeanClass) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
        HttpEntity<T> httpEntity = new HttpEntity<T>(requestBean, headers);

        try {
            ResponseEntity<U> result = null;
            log.info("------------------------------------------------");
            if (null == uriVariables) {
                URI uri = null;
                if (url.contains("@")) {
                    URL urlObj = new URL(url);
                    uri = new URI(urlObj.getProtocol(), null, urlObj.getHost(), urlObj.getPort(), urlObj.getPath(), urlObj.getQuery(), null);
                } else {
                    uri = URI.create(url);
                }
                log.info("真实发出URI地址为: {}", uri.getPath());
                result = restTemplate.exchange(uri, method, httpEntity, responseBeanClass);
            } else {
                log.info("真实发出Url地址为: {}", url);
                result = restTemplate.exchange(url, method, httpEntity, responseBeanClass, uriVariables);
            }
            log.info("------------------------------------------------");
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
